package com.icebartech.base.modules.user.api;

import com.icebartech.core.local.UserThreadLocal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import com.github.pagehelper.PageInfo;
import com.icebartech.base.modules.user.dto.AdminUserCoreDTO;
import com.icebartech.base.modules.user.dto.AdminUserInfoDTO;
import com.icebartech.base.modules.user.dto.AppPermissionInfoDTO;
import com.icebartech.base.modules.user.model.AdminUserCore;
import com.icebartech.base.modules.user.model.AdminUserLoginInfo;
import com.icebartech.base.modules.user.model.AppRole;
import com.icebartech.base.modules.user.param.RegisterParam;
import com.icebartech.base.modules.user.service.AdminUserCoreService;
import com.icebartech.base.modules.user.service.AdminUserLoginInfoService;
import com.icebartech.base.modules.user.service.AppPermissionService;
import com.icebartech.base.modules.user.service.AppRoleService;
import com.icebartech.core.annotations.RequireLogin;
import com.icebartech.core.components.LoginComponent;
import com.icebartech.core.constants.UserEnum;
import com.icebartech.core.controller.BaseController;
import com.icebartech.core.local.UserThreadLocal;
import com.icebartech.core.local.LocalUser;
import com.icebartech.core.utils.CommonUtil;
import com.icebartech.core.utils.ParamValidateUtil;
import com.icebartech.core.vo.BaseData;
import com.icebartech.core.vo.PageData;
import com.icebartech.core.vo.RespJson;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;

@Api(description = "后台用户管理接口")
@RestController
@RequestMapping(value = "/admin/user", produces = "application/json;charset=UTF-8")
public class AdminUserController extends BaseController {
    
    private static Logger logger = LoggerFactory.getLogger(AdminUserController.class);
    
    @Autowired
    private AdminUserCoreService adminUserCoreService;
    
    
    @Autowired
    private AppPermissionService appPermissionService;
    
    @Autowired
    private LoginComponent loginComponent;
    
    @Autowired
    private AdminUserLoginInfoService adminUserLoginInfoService;
    
    @Autowired
    private AppRoleService appRoleService;
    
    
    /**
     * @api {post} /admin/user/findAdminUserByPage 分页获取用户列表
     * @apiGroup admin-user
     * @apiName findAdminUserByPage
     * @apiDescription 分页获取用户列表
     * @apiParam {String} trueName 姓名，模糊，选填
     * @apiParam {String} mobile 手机，模糊，选填
     * @apiParam {int} pageIndex 第几页，必填
     * @apiParam {int} pageSize 每页大小，必填
     * @apiSuccessExample 成功返回:
     * {
     *     "status": "返回码，200：成功；500：失败；401：未登录",
     *     "msg": "提示信息",
     *     "data" : {
     *         "count":"总条数",
     *     	   "pageCount":"总分页数",
     *         "bussData" : [{
     *             "userId" : "Long-用户id",
     *             "userName" : "String-用户登录账户",
     *             "mobile" : "String-手机号",
     *             "trueName" : "String-真实姓名",
     *             "roleName" : "String-角色名称"
     *         }]
     *     }
     * }
     * @apiErrorExample 失败返回:
     * {
     *     "status": "返回码，200：成功；500：失败；401：未登录",
     *     "msg": "提示信息"
     * }
     */
    @ApiOperation("分页获取用户列表")
    @RequireLogin(userEnum = UserEnum.admin)
    @PostMapping(value = "/findAdminUserByPage")
    public RespJson<BaseData<List<AdminUserCoreDTO>>> findAdminUserByPage(
          @ApiParam("姓名，模糊，选填")
          @RequestParam(value = "trueName", required = false) String trueName,
          @ApiParam("手机，模糊，选填")
          @RequestParam(value = "mobile", required = false) String mobile,
          @ApiParam("第几页，必填")
          @RequestParam(value = "pageIndex") int pageIndex,
          @ApiParam("每页大小，必填")
          @RequestParam(value = "pageSize") int pageSize) {
        RespJson respJson = getFailRtnMap("发生未知错误！");
        
        Map<String, Object> paramMap = new HashMap<>();
        if (StringUtils.isNotEmpty(trueName)) {
            paramMap.put("trueName", trueName);
        }
        if (StringUtils.isNotEmpty(mobile)) {
            paramMap.put("mobile", mobile);
        }
        PageInfo<AdminUserCoreDTO> pageInfo = adminUserCoreService.findAdminUserCoreByPage(paramMap, pageIndex, pageSize);
        
        PageData pageData = new PageData((int) pageInfo.getTotal(), pageInfo.getPages(), pageInfo.getList());
        respJson = getSuccessPageRtnMap("获取角色列表成功！", pageData);
        return respJson;
    }
    
    
    /**
     * @api {post} /admin/user/findAdminUserDetailByUserId 获取用户详情信息
     * @apiGroup admin-user
     * @apiName findAdminUserDetailByUserId
     * @apiDescription 获取用户详情信息
     * @apiParam {Long} userId 用户id，必填
     * @apiSuccessExample 成功返回:
     * {
     *     "status": "返回码，200：成功；500：失败；401：未登录",
     *     "msg": "提示信息",
     *     "data" : {
     *         "count":"总条数",
     *     	   "pageCount":"总分页数",
     *         "bussData" : [{
     *             "userId" : "Long-用户id",
     *             "userName" : "String-用户登录账户",
     *             "mobile" : "String-手机号",
     *             "trueName" : "String-真实姓名",
     *             "roleName" : "String-角色名称"
     *         }]
     *     }
     * }
     * @apiErrorExample 失败返回:
     * {
     *     "status": "返回码，200：成功；500：失败；401：未登录",
     *     "msg": "提示信息"
     * }
     */
    @ApiOperation("获取用户详情信息")
    @RequireLogin(userEnum = UserEnum.admin)
    @PostMapping(value = "/findAdminUserDetailByUserId")
    public RespJson<BaseData<AdminUserCoreDTO>> findAdminUserDetailByUserId(
          @ApiParam("用户id，必填")
          @RequestParam(value = "userId") Long userId) {
        RespJson respJson = getFailRtnMap("发生未知错误！");
        
        AdminUserCoreDTO ext = adminUserCoreService.findUserCoreExtByUserId(userId);
        
        BaseData baseData = new BaseData(ext);
        respJson = getSuccessRtnMap("获取用户信息成功！", baseData);
        return respJson;
    }
    
    
    /**
     * @api {post} /admin/user/saveAdminUser 保存后台用户基本信息
     * @apiGroup admin-user
     * @apiParam {Long} userId 用户id，编辑时必填
     * @apiParam {String} userName 用户名，必填
     * @apiParam {String} nickname 昵称，选填
     * @apiParam {String} trueName 真实姓名，必填
     * @apiParam {String} mobile 手机号，必填
     * @apiParam {String} password 密码，必填，编辑时选填
     * @apiParam {String} confirmPassword 确认密码，必填，编辑时选填
     * @apiParam {Lomg} roleId 角色id，必填
     * @apiDescription 保存后台用户基本信息，编辑时不允许更改用户名和密码
     * @apiSuccessExample 成功返回:
     * {
     *     "status": "返回码，200：成功；500：失败；401：未登录",
     *     "msg": "提示信息",
     *     "data" : {
     *         "bussData" : null
     *     }
     * }
     * @apiErrorExample 失败返回:
     * {
     *     "status": "返回码，200：成功；500：失败；401：未登录",
     *     "msg": "提示信息",
     * }
     */
    @ApiOperation("保存后台用户基本信息")
    @RequireLogin(userEnum = UserEnum.admin)
    @PostMapping(value = "/saveAdminUser")
    public RespJson<BaseData> saveAdminUser(RegisterParam param, BindingResult result) {
        RespJson respJson = getFailRtnMap("发生未知错误，请稍后重试！");
        if (result.hasErrors()) {
            respJson = getFailRtnMap(result.getFieldError().getDefaultMessage());
            return respJson;
        }
        
        if (param.getUserId() != null) {
            //更新用户信息
            AdminUserCore update = new AdminUserCore();
            update.setUserId(param.getUserId());
            update.setTrueName(param.getTrueName());
            update.setMobile(param.getMobile());
            update.setAppRoleId(String.valueOf(param.getRoleId()));
            adminUserCoreService.updateSelective(update);
            respJson = getSuccessRtnMap("更新用户信息成功！", null);
            return respJson;
        }
        
        if (!param.getPassword().equals(param.getConfirmPassword())) {
            respJson = getFailRtnMap("两次输入的密码不一致！");
            return respJson;
        }
        
        //检查该用户名是否已存在
        boolean existsFlag = adminUserCoreService.checkUserName(param.getUserName());
        if (existsFlag) {
            respJson = getFailRtnMap("该用户名已存在，请更换！");
            return respJson;
        }
        Date date = new Date();
        //用户基本信息
        AdminUserCore userCore = new AdminUserCore();
        userCore.setCreator("[SYS]");
        userCore.setMemberType((short) 0);
        userCore.setModifier("[SYS]");
        userCore.setTrueName(param.getTrueName());
        userCore.setUserName(param.getUserName());
        userCore.setMobile(param.getMobile());
        userCore.setAppRoleId(String.valueOf(param.getRoleId()));
        
        //用户登录信息
        AdminUserLoginInfo loginInfo = new AdminUserLoginInfo();
        loginInfo.setLoginName(param.getUserName());
        loginInfo.setPwd(param.getPassword());
        String ip = loginComponent.getRemoteIP(getRequest());
        loginInfo.setRegIp(ip);
        loginInfo.setLastLoginIp(ip);
        loginInfo.setLastLoginTime(date);
        loginInfo.setCreator("[SYS]");
        loginInfo.setModifier("[SYS]");
        
        AdminUserCore registerAppUser = adminUserCoreService.registerAdminUserCore(userCore, loginInfo);
        if (registerAppUser != null) {
            //保存门店与账号关联记录
            respJson = getSuccessRtnMap("保存用户基本信息成功！", null);
        } else {
            respJson = getFailRtnMap("保存用户基本信息失败，请稍后重试！");
        }
        return respJson;
    }
    
    
    /**
     * @api {post} /admin/user/findUserPermissions 获取用户拥有的左侧菜单权限
     * @apiGroup admin-user
     * @apiName findUserPermissions
     * @apiDescription 获取用户拥有的左侧菜单权限，说明：
     * 1. 用户登录后台后即调用该接口获取左侧的菜单权限，拿到哪些就是哪些，并且已经进行排序；
     * 2. 因为超级管理员的员工和门店管理员的页面是可以复用的，只是超级管理员的总后台会多一个门店选择的下拉组件，请根据登录接口返回的用户拥有的权限（super_admin为超级管理员）来控制是否显示门店下拉选择；
     * @apiSuccessExample 成功返回:
     * {
     *     "status": "返回码，200：成功；500：失败；401：未登录",
     *     "msg": "提示信息",
     *     "data" : {
     *         "bussData" : [{
     *             "id" : "Long-权限id",
     *             "permissionName" : "String-权限名称",
     *             "resourceId" : "String-关联的资源id",
     *             "permissionType" : "String-权限类型（page:页面；ajax:ajax请求；button：按钮）",
     *             "roleType" : "String-角色类型",
     *             "menuUrl" : "String-菜单url，当权限类型为页面时有值返回",
     *             "menuName" : "String-菜单名称，当权限类型为页面时有值返回",
     *             "menuLevel" : "String-第几级菜单，当权限类型为页面时有值返回",
     *             "childPermissions" : [{//子权限菜单列表
     *                 "id" : "Long-权限id",
     *                 "permissionName" : "String-权限名称",
     *                 "resourceId" : "String-关联的资源id",
     *                 "permissionType" : "String-权限类型（page:页面；ajax:ajax请求；button：按钮）",
     *                 "roleType" : "String-角色类型",
     *                 "menuUrl" : "String-菜单url，当权限类型为页面时有值返回",
     *                 "menuName" : "String-菜单名称，当权限类型为页面时有值返回",
     *                 "menuLevel" : "String-第几级菜单，当权限类型为页面时有值返回"
     *             }]
     *         }]
     *     }
     * }
     * @apiErrorExample 失败返回:
     * {
     *     "status": "返回码，200：成功；500：失败；401：未登录",
     *     "msg": "提示信息"
     * }
     */
    @ApiOperation("获取用户拥有的左侧菜单权限")
    @RequireLogin(userEnum = UserEnum.admin)
    @PostMapping(value = "/findUserPermissions")
    public RespJson<BaseData<List<AppPermissionInfoDTO>>> findUserPermissions() {
        RespJson  respJson = getFailRtnMap("发生未知错误！");
        LocalUser user     = UserThreadLocal.getUserInfo();
        Long      userId   = user.getUserId();
        
        List<AppPermissionInfoDTO> dataList = appPermissionService.findUserPermissions(userId);
        BaseData                   baseData = new BaseData(dataList);
        respJson = getSuccessRtnMap("获取用户菜单权限列表成功！", baseData);
        return respJson;
    }
    
    /**
     * @api {post} /admin/user/deleteAdminUserByUserId 删除后台用户
     * @apiGroup admin-user
     * @apiName deleteAdminUserByUserId
     * @apiDescription 删除后台用户
     * @apiParam {Long} userId 用户id，即列表返回的userId字段，必填
     * @apiSuccessExample 成功返回:
     * {
     *     "status": "返回码，200：成功；500：失败；401：未登录",
     *     "msg": "提示信息",
     *     "data" : {
     *         "bussData" : null
     *     }
     * }
     * @apiErrorExample 失败返回:
     * {
     *     "status": "返回码，200：成功；500：失败；401：未登录",
     *     "msg": "提示信息"
     * }
     */
    @ApiOperation("删除后台用户")
    @RequireLogin(userEnum = UserEnum.admin)
    @PostMapping(value = "/deleteAdminUserByUserId")
    public RespJson<BaseData> deleteAdminUserByUserId(
          @ApiParam("用户id，即列表返回的userId字段，必填")
          @RequestParam(value = "userId") Long userId) {
        RespJson respJson = getFailRtnMap("发生未知错误！");
        if (userId == null) {
            return getFailRtnMap("用户ID不能为空！");
        }
        boolean flag = adminUserCoreService.deleteAdminUser(userId);
        if (flag) {
            respJson = getSuccessRtnMap("删除用户信息成功！", null);
        } else {
            respJson = getFailRtnMap("删除用户信息失败！");
        }
        return respJson;
    }
    
    
    /**
     * @api {post} /admin/user/login 后台用户登录
     * @apiGroup admin-login
     * @apiParam {String} userName 用户名，必填
     * @apiParam {String} password 密码，必填
     * @apiDescription 后台用户登录，登录成功后会返回sessionId和对应的基本信息，sessionId应该缓存在客户端，后续接口调用通过请求传递过来，后台系统现在也采用前后端分离了，将抛弃之前的cookie机制，采用类似小程序的登录机制
     * @apiSuccessExample 成功返回:
     * {
     *     "status": "返回码，200：成功；500：失败；401：未登录",
     *     "msg": "提示信息",
     *     "data" : {
     *         "bussData" : {
     *             "sessionId" : "String-后台会话id，该id由服务端生成，前端应使用localStorage进行缓存起来，并在后续的接口请求中传递过来，并且该sessionId如果没操作的话，其有效期为：30分钟",
     *             "userId" : "Long-后台用户id",
     *             "userName" : "String-后台用户账号",
     *             "mobile" : "String-用户手机",
     *             "trueName" : "String-真实姓名",
     *             "avatarUrl" : "String-头像地址",
     *             "customerId" : "Long-所属门店id",
     *             "storeName" : "String-所属门店名称"
     *         }
     *     }
     * }
     * @apiErrorExample 失败返回:
     * {
     *     "status": "返回码，200：成功；500：失败；401：未登录",
     *     "msg": "提示信息",
     * }
     */
    @ApiOperation("后台用户登录")
    @PostMapping(value = "/login")
    public RespJson<BaseData<AdminUserInfoDTO>> login(
          @ApiParam("用户名，必填")
          @RequestParam(value = "userName") String userName,
          @ApiParam("密码，必填")
          @RequestParam(value = "password") String password) {
        RespJson respJson = getFailRtnMap("发生未知错误！");
        if (StringUtils.isEmpty(userName)) {
            respJson = getFailRtnMap("用户名不能为空！");
            return respJson;
        } else if (StringUtils.isEmpty(password)) {
            respJson = getFailRtnMap("密码不能为空！");
            return respJson;
        }
        AdminUserLoginInfo loginInfo = adminUserLoginInfoService.findLoginInfoByName(userName);
        if (loginInfo == null) {
            //用户名不存在
            respJson = getFailRtnMap("用户名不存在，请重试！");
            return respJson;
        }
        AdminUserCore userCore = adminUserCoreService.findById(loginInfo.getUserId());
        if (userCore == null) {
            respJson = getFailRtnMap("用户不存在或状态异常！");
            return respJson;
        }
        final String pwd   = loginInfo.getPwd();//加密密码
        final String pwd_2 = loginInfo.getPwd2();
        if (StringUtils.isNotEmpty(pwd) && StringUtils.isNotEmpty(pwd_2) && StringUtils.isNotEmpty(password) && !CommonUtil.validatePwdMD5(pwd, password, pwd_2)) {
            //登录写sessionId
            String sessionId = UUID.randomUUID().toString();
            logger.info("admin user login success, userId is {}.", loginInfo.getUserId());
            AdminUserInfoDTO userInfo  = new AdminUserInfoDTO();
            String           avatarUrl = adminUserCoreService.getUserAvatarUrl(userCore.getUserId());
            userInfo.setAvatarUrl(avatarUrl);
            userInfo.setMobile(userCore.getMobile());
            userInfo.setSessionId(sessionId);
            userInfo.setTrueName(userCore.getTrueName());
            userInfo.setUserId(userCore.getUserId());
            userInfo.setUserName(userCore.getUserName());
            
            String roleKey = null;
            if (userCore.getAppRoleId() != null) {
                AppRole appRole = appRoleService.findById(Long.valueOf(userCore.getAppRoleId()));
                if (appRole != null) {
                    roleKey = appRole.getRoleKey();
                }
                List<String> roleKeys = new ArrayList<>();
                roleKeys.add(roleKey);
                userInfo.setRoleKeys(roleKeys);
            }
            
            loginComponent.adminLogin(sessionId, userInfo.getUserId());
            
            BaseData baseData = new BaseData(userInfo);
            respJson = getSuccessRtnMap("用户登录成功！", baseData);
        } else {
            respJson = getFailRtnMap("密码错误，请重新输入！");
        }
        return respJson;
    }
    
    /**
     * @api {post} /admin/user/logout 后台用户登出
     * @apiGroup admin-login
     * @apiDescription 后台用户登出
     * @apiSuccessExample 成功返回:
     * {
     *     "status": "返回码，200：成功；500：失败；401：未登录",
     *     "msg": "提示信息",
     *     "data" : {
     *         "bussData" : {
     *
     *         }
     *     }
     * }
     * @apiErrorExample 失败返回:
     * {
     *     "status": "返回码，200：成功；500：失败；401：未登录",
     *     "msg": "提示信息",
     * }
     */
    @ApiOperation("后台用户登出")
    @RequireLogin(userEnum = UserEnum.admin)
    @PostMapping(value = "/logout")
    public RespJson<BaseData> logout() {
        RespJson  respJson = getFailRtnMap("发生未知错误！");
        LocalUser user     = UserThreadLocal.getUserInfo();
        loginComponent.adminLogout(user.getSessionId());
        respJson = getSuccessRtnMap("登出成功！", null);
        return respJson;
    }
    
    
    /**
     * @api {post} /admin/user/updUserPWD 后台用户修改密码
     * @apiGroup admin-login
     * @apiParam {String} oldPWD 旧密码，必填
     * @apiParam {String} newPWD 新密码，必填
     * @apiParam {String} confirmNewPWD 确认新密码，必填
     * @apiDescription 后台用户修改密码
     * @apiSuccessExample 成功返回:
     * {
     *     "status": "返回码，200：成功；500：失败；401：未登录",
     *     "msg": "提示信息",
     *     "data" : {
     *         "bussData" : {
     *
     *         }
     *     }
     * }
     * @apiErrorExample 失败返回:
     * {
     *     "status": "返回码，200：成功；500：失败；401：未登录",
     *     "msg": "提示信息",
     * }
     */
    @ApiOperation("后台用户修改密码")
    @RequireLogin(userEnum = UserEnum.admin)
    @PostMapping(value = "/updUserPWD")
    public RespJson<BaseData<Boolean>> updUserPWD(
          @ApiParam("旧密码，必填")
          @RequestParam(value = "oldPWD") String oldPWD,
          @ApiParam("新密码，必填")
          @RequestParam(value = "newPWD") String newPWD,
          @ApiParam("确认新密码，必填")
          @RequestParam(value = "confirmNewPWD") String confirmNewPWD) {
    	RespJson<BaseData<Boolean>> rtnMap = getFailRtnMap("发生未知错误，请稍后重试！");
        
        if (StringUtils.isBlank(oldPWD)) {
            return getFailRtnMap("旧密码不能为空！");
        } else if (StringUtils.isBlank(newPWD)) {
            return getFailRtnMap("新密码不能为空！");
        } else if (StringUtils.isBlank(confirmNewPWD)) {
            return getFailRtnMap("确认密码不能为空！");
        } else if (!ParamValidateUtil.validatePwd(oldPWD)) {
            return getFailRtnMap("密码必须为6-12位的字母或数字！");
        } else if (!ParamValidateUtil.validatePwd(newPWD)) {
            return getFailRtnMap("密码必须为6-12位的字母或数字！");
        } else if (!newPWD.equals(confirmNewPWD)) {
            return getFailRtnMap("两次新密码不一样！");
        }
        
        LocalUser          user      = UserThreadLocal.getUserInfo();
        Long               userId    = user.getUserId();
        AdminUserLoginInfo loginInfo = adminUserLoginInfoService.findById(userId);
        
        final String pwd   = loginInfo.getPwd();//加密密码
        final String pwd_2 = loginInfo.getPwd2();
        if (StringUtils.isNotEmpty(pwd) && StringUtils.isNotEmpty(pwd_2) && StringUtils.isNotEmpty(oldPWD) && !CommonUtil.validatePwdMD5(pwd, oldPWD, pwd_2)) {
            if (adminUserLoginInfoService.updateUserPassword(userId, newPWD)) {
                loginComponent.adminLogout(user.getSessionId());
                BaseData<Boolean> baseData = new BaseData<>(true);
                return getSuccessRtnMap("修改密码成功", baseData);
            }
        } else {
            return getFailRtnMap("旧密码不正确，请重试！");
        }
        return rtnMap;
    }
    
}
